package com.tnovoselec.android.travelassistant.activity;

import android.app.ProgressDialog;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.ViewFlipper;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MyLocationOverlay;
import com.j256.ormlite.dao.Dao;
import com.nth.android.ar.ARAugmentedView;
import com.nth.android.ar.ARCameraView;
import com.tnovoselec.android.common.async.Async;
import com.tnovoselec.android.common.async.listener.Outcome;
import com.tnovoselec.android.common.async.notif.NotifierFactory;
import com.tnovoselec.android.common.util.ApplicationUtil;
import com.tnovoselec.android.lbs.location.MyLocationService;
import com.tnovoselec.android.orm.apptools.OrmLiteBaseFragmentMapActivity;
import com.tnovoselec.android.travelassistant.Config;
import com.tnovoselec.android.travelassistant.R;
import com.tnovoselec.android.travelassistant.adapter.AbstractAdapter;
import com.tnovoselec.android.travelassistant.async.TravelAssistantGeocoder;
import com.tnovoselec.android.travelassistant.db.TravelAssistantDatabaseHelper;
import com.tnovoselec.android.travelassistant.dto.BankomatDto;
import com.tnovoselec.android.travelassistant.dto.IGeoPoint;
import com.tnovoselec.android.travelassistant.overlay.AbstractMapOverlay;
import com.tnovoselec.android.travelassistant.view.CustomMapView;
import com.tnovoselec.android.travelassistant.view.CustomMapView.OnMapMovedListener;
import com.tnovoselec.android.travelassistant.view.CustomMapView.OnZoomLevelChangeLister;
import com.tnovoselec.android.ui.quickaction.QuickAction;
import com.tnovoselec.android.ui.quickaction.QuickAction.OnActionItemClickListener;

public abstract class AbstractMapActivity extends OrmLiteBaseFragmentMapActivity<TravelAssistantDatabaseHelper> implements OnMapMovedListener,
		AnimationListener, OnItemClickListener, OnClickListener, LocationListener, OnZoomLevelChangeLister, OnKeyListener, OnActionItemClickListener {

	public enum VIEWS {
		MAP, LIST, AR
	}

	public static String TAG = AbstractMapActivity.class.getSimpleName();

	protected String activeType = "";

	CustomMapView mapView;
	protected ProgressDialog dialog = null;
	protected Handler handler = new Handler();
	protected Dao<IGeoPoint, String> poiDao = null;
	protected AbstractMapOverlay<IGeoPoint> mapOverlay;
	protected MyLocationOverlay locationOverlay;
	protected MyLocationService locationService = null;
	protected ARCameraView arCameraView;
	protected ARAugmentedView arAugmentedView;
	protected ListView list;
	protected Location lastLocation;
	protected ViewFlipper viewFlipper;
	protected AbstractAdapter<IGeoPoint> adapter;

	protected View searchContainer;
	protected EditText query;
	protected ImageView cancel;
	protected ImageButton mapMode;
	protected ImageButton listMode;
	protected ImageButton arMode;

	protected Animation animShow;
	protected Animation animHide;

	protected QuickAction quickAction;
	protected View itemChooser;

	/*
	 * private static final int ZABA_ID = 1; private static final int PBZ_ID =
	 * 2; private static final int HPB_ID = 3; private static final int HYPO_ID
	 * = 4; private static final int SPLITSKA_ID = 5; private static final int
	 * OTP_ID = 6; private static final int ERSTE_ID = 7; private static final
	 * int RBA_ID = 8; private static final int ALL_ID = 9;
	 */
	protected boolean isSearchActivated = false;
	protected boolean lock = false;
	protected boolean locationRequested = false;

	protected static final Criteria CRITERIA = new Criteria();
	static {
		CRITERIA.setAccuracy(Criteria.ACCURACY_COARSE);
		CRITERIA.setAltitudeRequired(false);
		CRITERIA.setBearingRequired(false);
		CRITERIA.setCostAllowed(true);
		CRITERIA.setSpeedRequired(false);
		CRITERIA.setPowerRequirement(Criteria.NO_REQUIREMENT);
	}

	@SuppressWarnings("deprecation")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
		super.onCreate(savedInstanceState);
		setContentView(R.layout.bankomati_map);

		try {
			poiDao = getDao();
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}
		viewFlipper = (ViewFlipper) findViewById(R.id.bankomati_viewflipper);
		list = (ListView) findViewById(R.id.bankomati_list);

		searchContainer = findViewById(R.id.search_popup_container);
		searchContainer.bringToFront();

		query = (EditText) findViewById(R.id.search_popup_edittext);
		query.setOnKeyListener(this);

		cancel = (ImageView) findViewById(R.id.search_popup_cancel);
		cancel.setOnClickListener(this);

		mapMode = (ImageButton) findViewById(R.id.bankomati_map_mode);
		listMode = (ImageButton) findViewById(R.id.bankomati_list_mode);
		arMode = (ImageButton) findViewById(R.id.bankomati_ar_mode);

		mapMode.setOnClickListener(this);
		listMode.setOnClickListener(this);
		arMode.setOnClickListener(this);

		list.setOnItemClickListener(this);

		mapView = (CustomMapView) findViewById(R.id.bankomati_map);
		mapView.setSatellite(false);
		mapView.setStreetView(false);
		// mapView.setBuiltInZoomControls(true);

		locationOverlay = new MyLocationOverlay(this, mapView);
		mapView.getOverlays().add(locationOverlay);
		// mapView.getController().setZoom(13);
		mapView.animateTo(new GeoPoint((int) (Config.zgLat * 1e6), (int) (Config.zgLng * 1e6)));

		mapView.invalidate();

		locationService = new MyLocationService(this, this, CRITERIA);

		arCameraView = (ARCameraView) findViewById(R.id.bankomati_ar_camera_view);
		arAugmentedView = (ARAugmentedView) findViewById(R.id.bankomati_ar_augmented_view);
		arAugmentedView.setShowRadar(true);
		arAugmentedView.setRadarPoiResourceId(R.drawable.poi_radar);
		arAugmentedView.setRadarBackgroundResourceId(R.drawable.background_ar_radar);

		adapter = getAdapter();
		list.setAdapter(adapter);
		animShow = AnimationUtils.loadAnimation(this, R.anim.popup_show);
		animHide = AnimationUtils.loadAnimation(this, R.anim.popup_hide);
		animHide.setAnimationListener(this);

		quickAction = new QuickAction(this, QuickAction.VERTICAL);
		populateQuickAction();


		search(MyLocationService.getLastKnownGeoPoint(this), VIEWS.MAP);
	}

	@Override
	protected void onResume() {
		super.onResume();
		arAugmentedView.start();
		arAugmentedView.setLocation(MyLocationService.getLastKnownLocation(this));
		try {
			if (locationOverlay != null) {
				locationOverlay.enableMyLocation();
				// locationOverlay.enableCompass();
			}
			if (locationService != null) {
				locationService.trackMyLocation();
			}
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}
		mapView.registerOnMapMovedListener(this);
		mapView.registerOnZoomLevelChangedListener(this);
	}

	@Override
	protected void onPause() {
		overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
		super.onPause();
		arAugmentedView.stop();
		try {
			if (locationOverlay != null) {
				locationOverlay.disableMyLocation();
				locationOverlay.disableCompass();
			}
			if (locationService != null) {
				locationService.stopTrackingMyLocation();
			}

		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}
		mapView.unregisterOnMapMovedListener();
		mapView.unregisterOnZoomChangedListener();
		mapOverlay.hidePopup();
	}

	@Override
	public void onZoomLevelChanged(int oldZoomLevel, int newZoomLevel) {
		Log.i(TAG, "Zoom changed from " + oldZoomLevel + " to " + newZoomLevel);

	}

	protected Runnable updateMap = getUpdateMapRunnable();

	@Override
	public void onLocationChanged(Location location) {
		int geoLat = (int) (location.getLatitude() * 1E6);
		int geoLng = (int) (location.getLongitude() * 1E6);
		Log.e(TAG, "Location received: " + location.toString());
		// mapView.getController().setZoom(10);
		mapView.animateTo(new GeoPoint(geoLat, geoLng));

		mapView.invalidate();

		if (location != null) {
			if (lastLocation == null) {
				lastLocation = location;
			}
			float[] distance = new float[3];
			Location.distanceBetween(lastLocation.getLatitude(), lastLocation.getLongitude(), location.getLatitude(), location.getLongitude(), distance);
			if (viewFlipper.getDisplayedChild() == 2) {
				search(MyLocationService.getLastKnownGeoPoint(this), VIEWS.AR);
			} else {
				mapView.getOverlays().add(locationOverlay);
				locationService.stopTrackingMyLocation();
				if (locationRequested) {
					search(MyLocationService.getLastKnownGeoPoint(this), VIEWS.MAP);
					locationRequested = false;
				}
			}
		}

	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// NIX

	}

	@Override
	public void onProviderEnabled(String provider) {
		// NIX

	}

	@Override
	public void onProviderDisabled(String provider) {
		// NIX

	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		viewFlipper.setDisplayedChild(0);
		IGeoPoint item = (BankomatDto) adapter.getItem(position);
		if (mapOverlay != null) {
			mapOverlay.handleListClick(item);
		}
	}

	@Override
	public void onClick(View v) {

		if (v == mapMode) {
			hideSearchPopup();
			viewFlipper.setDisplayedChild(0);
			// search(MyLocationService.getLastKnownGeoPoint(this), VIEWS.MAP);
			search(mapView.getCurrentMiddlePoint(), VIEWS.MAP);
		} else if (v == listMode) {
			hideSearchPopup();
			viewFlipper.setDisplayedChild(1);
			updateList();
		} else if (v == arMode) {
			hideSearchPopup();
			viewFlipper.setDisplayedChild(2);
			search(MyLocationService.getLastKnownGeoPoint(this), VIEWS.AR);
		} else if (v == cancel) {
			hideSearchPopup();
		} else if (v == itemChooser) {
			quickAction.show(v);
		}
		mapOverlay.hidePopup();
	}

	protected void showSearchPopup() {
		if (!isSearchActivated) {
			searchContainer.setVisibility(View.VISIBLE);
			searchContainer.startAnimation(animShow);
			if (query != null) {
				query.requestFocus();
			}
			isSearchActivated = true;
		}
	}

	protected void hideSearchPopup() {
		if (isSearchActivated) {

			searchContainer.startAnimation(animHide);
		}
	}

	@Override
	public void onAnimationStart(Animation animation) {
		// NIX

	}

	@Override
	public void onAnimationEnd(Animation animation) {
		if (animation == animHide) {
			searchContainer.setVisibility(View.GONE);
			isSearchActivated = false;
			if (query != null) {
				query.setText("");
			}
		}

	}

	@Override
	public void onAnimationRepeat(Animation animation) {
		// NIX

	}

	@Override
	public boolean onKey(View v, int keyCode, KeyEvent event) {
		if (event.getAction() == KeyEvent.ACTION_UP)
			return false;

		if (keyCode == KeyEvent.KEYCODE_ENTER) {

			if (!TextUtils.isEmpty(query.getText())) {
				if (!lock) {
					lock = true;
					InputMethodManager mgr = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
					mgr.hideSoftInputFromWindow(query.getWindowToken(), 0);
					try {
						String address = query.getText().toString();
						if (address != null && address.length() > 0) {
							Async.doAsync(null, new TravelAssistantGeocoder(this, address), new Outcome<Void, GeoPoint>() {

								@Override
								protected void succeeded(Void key, GeoPoint result) {
									Log.i(TAG, result.getLatitudeE6() + " " + result.getLongitudeE6());
									search(result, VIEWS.MAP);
									hideSearchPopup();
									lock = false;
								}

								@SuppressWarnings("synthetic-access")
								@Override
								protected void failed(Void key, Throwable t) {
									Toast.makeText(AbstractMapActivity.this, getString(R.string.no_result), Toast.LENGTH_SHORT).show();
									lock = false;
									hideSearchPopup();
								}
							}, NotifierFactory.newThreadSpecificNotifier(handler));
						}
					} catch (Exception e) {
						Log.e(TAG, e.getMessage());
					}
				}

			} else {
				Toast.makeText(this, getString(R.string.no_result), Toast.LENGTH_SHORT).show();
				lock = false;

			}
			return true;
		}

		return false;
	}

	@Override
	protected void onStart() {
		super.onStart();
		ActionBar bar = getSupportActionBar();
		if (bar != null) {
			bar.setDisplayHomeAsUpEnabled(true);
		}
	}

	@Override
	public void onItemClick(QuickAction source, int pos, int actionId) {
		if (source == quickAction) {
			/*
			 * Log.i(TAG, "item clicked: " + actionId); if (actionId == ZABA_ID)
			 * { activeType = Constant.ZABA_REGEX; } else if (actionId ==
			 * PBZ_ID) { activeType = Constant.PBZ_REGEX; } else if (actionId ==
			 * HPB_ID) { activeType = Constant.HPB_REGEX; } else if (actionId ==
			 * HYPO_ID) { activeType = Constant.HYPO_REGEX; } else if (actionId
			 * == ERSTE_ID) { activeType = Constant.ERSTE_REGEX; } else if
			 * (actionId == RBA_ID) { activeType = Constant.RBA_REGEX; } else if
			 * (actionId == SPLITSKA_ID) { activeType = Constant.SPLITSKA_REGEX;
			 * } else if (actionId == OTP_ID) { activeType = Constant.OTP_REGEX;
			 * } else if (actionId == ALL_ID) { activeType = ""; }
			 */
			// search(MyLocationService.getLastKnownGeoPoint(this), VIEWS.MAP);
			if (viewFlipper.getDisplayedChild() == 0) {
				search(mapView.getCurrentMiddlePoint(), VIEWS.MAP);
			} else if (viewFlipper.getDisplayedChild() == 1) {
				search(mapView.getCurrentMiddlePoint(), VIEWS.LIST);
			} else if (viewFlipper.getDisplayedChild() == 2) {
				search(mapView.getCurrentMiddlePoint(), VIEWS.AR);
			}
		}

	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == R.id.menu_search) {
			if (viewFlipper.getDisplayedChild() != 0) {
				viewFlipper.setDisplayedChild(0);

			}
			if (isSearchActivated) {
				hideSearchPopup();
			} else {
				showSearchPopup();
			}

		} else if (item.getItemId() == R.id.menu_more) {
			quickAction.show(itemChooser);
		} else if (item.getItemId() == android.R.id.home) {
			finish();
		} else if (item.getItemId() == R.id.menu_locate_me) {
			Log.e(TAG, "Searching for location");
			if (ApplicationUtil.isGpsEnabled(this)) {
				if (locationService != null) {
					locationService.trackMyLocation();
					locationRequested = true;
				}
			} else {
				Toast.makeText(this, R.string.enable_gps, Toast.LENGTH_SHORT).show();
			}
		}
		mapOverlay.hidePopup();
		return true;

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getSupportMenuInflater().inflate(R.menu.map_menu, menu);
		for (int i = 0; i < menu.size(); i++) {
			MenuItem item = menu.getItem(i);
			if (item.getItemId() == R.id.menu_more) {
				itemChooser = item.getActionView();
				if (itemChooser != null) {
					itemChooser.setOnClickListener(this);
				}
			}
		}
		return super.onCreateOptionsMenu(menu);
	}

	public abstract Dao<IGeoPoint, String> getDao();

	public abstract AbstractAdapter<IGeoPoint> getAdapter();

	public abstract void populateQuickAction();

	protected abstract void search(final GeoPoint geoPoint, final VIEWS view);

	public abstract Runnable getUpdateMapRunnable();

	public abstract void updateList();

}
